package cn.com.surker.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 时间帮助类
 */
public class DateUtil {

	/**
	 * 完整的时间格式
	 */
	public static final String DATE_DETAIL_FORMATTER = "yyyy-MM-dd HH:mm:ss";

	public static final String DATE_DETAIL_FORMATTER_SHORT = "yyyy-MM-dd HH:mm";


	/**
	 * 中文格式
	 */
	public static final String DATE_DETAIL_FORMATTER_CHINESE = "yyyy年MM月dd日HH时mm分ss秒";

	public static final String DATE_DETAIL_FORMATTER_CHINESE_TIME = "HH时mm分ss秒";

	public static final String DATE_DETAIL_FORMATTER_CHINESE_DATE = "yyyy年MM月dd日";

	public static final String DATE_DETAIL_FORMATTER_CHINESE_DATE2 = "yyyy年MM月dd";

	/**
	 * 简写的日期格式
	 */
	public static final String DATE_ABBR_FORMATTER = "yyyy-MM-dd";

	public static final String DATE_MONTH_FORMATTER = "yyyy-MM";

    private static String DATE_VALIDATION1 = "\\d{4}-\\d{2}-\\d{2}";
    private static String DATE_VALIDATION2 = "\\d{4}/\\d{2}/\\d{2}";
    private static String DATE_VALIDATION3 = "\\d{4}年\\d{2}月\\d{2}日";
    private static String BASE_TIME_VALIDATION1 = " \\d{2}:\\d{2}:\\d{2}";
    private static String BASE_TIME_VALIDATION2 = " \\d{2}时\\d{2}分\\d{2}秒";
    private static String DATE_VALIDATION4 = DATE_VALIDATION1 + BASE_TIME_VALIDATION1;
    private static String DATE_VALIDATION5 = DATE_VALIDATION2 + BASE_TIME_VALIDATION1;
    private static String DATE_VALIDATION6 = DATE_VALIDATION3 + BASE_TIME_VALIDATION1;
    private static String DATE_VALIDATION7 = DATE_VALIDATION1 + BASE_TIME_VALIDATION2;
    private static String DATE_VALIDATION8 = DATE_VALIDATION2 + BASE_TIME_VALIDATION2;
    private static String DATE_VALIDATION9 = DATE_VALIDATION3 + BASE_TIME_VALIDATION2;
    public static final String[] DEFAULT_DATE_VALIDATION = new String[]{DATE_VALIDATION1, DATE_VALIDATION2, DATE_VALIDATION3,
            DATE_VALIDATION4,DATE_VALIDATION5,DATE_VALIDATION6,DATE_VALIDATION7,DATE_VALIDATION8,DATE_VALIDATION9};
	/**
	 * 简写的时间格式
	 */
	public static final String TIME_ABBR_FORMATTER = "HH:mm:ss";

	public static final String[] DEFAULT_FORMAT_PATTERS = new String[]{DATE_DETAIL_FORMATTER_CHINESE_DATE, DATE_ABBR_FORMATTER, DATE_DETAIL_FORMATTER_CHINESE_DATE2, DATE_DETAIL_FORMATTER};

    static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 判断是否是日期格式
     * @param value
     * @return
     */
    public static Boolean isDateTime(String value) {
        if (StringUtils.isNull(value))
            return false;
        for (int i = 0; i < DEFAULT_DATE_VALIDATION.length; i++) {
            Boolean boo = Pattern.matches(DEFAULT_DATE_VALIDATION[i], value);
            if (boo)
                return boo;
        }
        return false;
    }

    /**
     * 根据当前日期计算属于第几周
     * @param nowTime yyyy-MM-dd
     * @param day 第几日
     * @return
     */
    public static Integer getMonthOfWeek(String nowTime, Integer day) {
        Integer monthFlag = 0;//默认为本月
        Integer tempDay = StringUtils.convertInteger(nowTime.substring(nowTime.lastIndexOf("-") + 1));
        if (tempDay > day)
            monthFlag = 1;//第二月
        Date nowDate = convertDate(nowTime, "yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(nowDate);
        int intWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;//星期几 0代表星期天
        Date startMonth = convertDate(nowTime.substring(0, 7) + "-" + day, "yyyy-MM-dd");//转换每月第一天时间
        if (monthFlag == 0)
            startMonth = convertBeforeMonthDate(startMonth, 1);//上个月的开始时间
        Integer differentDay = differentDays(startMonth, nowDate);//计算相差多少天
        Integer week = differentDay / 7;
        if (intWeek > 0)
            week++;
        return week;
    }

    public static long currentTimeSeconds() {
        return System.currentTimeMillis() / 1000;
    }

    /**
     * 判断两个时间相差多少天
     * @param date1
     * @param date2
     * @return
     */
    public synchronized static Integer differentHour(Date date1, Date date2) {
        Long diff = date2.getTime() - date1.getTime();
        Long diffDay = 1000 * 24 * 60 * 60L;
        Long diffHour = 1000 * 60 * 60L;
        Integer hour = convertInteger(diff / diffHour);
        hour = Math.abs(hour);
        return hour;
    }

    /**
     * 判断两个时间相差多少分
     * @param date1
     * @param date2
     * @return
     */
    public synchronized static Integer differentMin(Date date1, Date date2) {
        Long diff = date2.getTime() - date1.getTime();
        Long diffDay = 1000 * 24 * 60 * 60L;
        Long diffMin = 1000 * 60L;
        Integer hour = convertInteger(diff / diffMin);
        hour = Math.abs(hour);
        return hour;
    }
    /**
     * 判断两个时间相差多少秒
     * @param date1
     * @param date2
     * @return
     */
    public synchronized static Integer differentSecond(Date date1, Date date2) {
        Long diff = date2.getTime() - date1.getTime();
        Long diffDay = 1000 * 24 * 60 * 60L;
        Long diffMin = 1000L;
        Integer hour = convertInteger(diff / diffMin);
        hour = Math.abs(hour);
        return hour;
    }
    /**
     * 判断两个时间相差多少分
     * @param date1
     * @param date2
     * @return
     */
    public synchronized static Integer differentMins(Date date1, Date date2) {
        Long diff = date2.getTime() - date1.getTime();
        Long diffDay = 1000 * 24 * 60 * 60L;
        Long diffMin = 1000 * 60L;
        Integer hour = convertInteger(diff / diffMin);
        hour = Math.abs(hour);
        return hour;
    }

    /**
     * 判断两个时间相差多少天
     * @param date1
     * @param date2
     * @return
     */
	@Deprecated
	public synchronized static int differentDays(Date date1, Date date2) {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);

        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);
        int day1= cal1.get(Calendar.DAY_OF_YEAR);
        int day2 = cal2.get(Calendar.DAY_OF_YEAR);

        int year1 = cal1.get(Calendar.YEAR);
        int year2 = cal2.get(Calendar.YEAR);
        if(year1 != year2) {  //同一年
            int timeDistance = 0 ;
            for(int i = year1 ; i < year2 ; i ++) {
                if(i%4==0 && i%100!=0 || i%400==0) {    //闰年
                    timeDistance += 366;
                } else {   //不是闰年
                    timeDistance += 365;
                }
            }
            return timeDistance + (day2-day1) ;
        } else {   //不同年
            return day2-day1;
        }
    }

	/**
	 * 计算两个date中的天数差,计算方式为date1 - date2
	 *
	 * @param date1
	 * @param date2
	 * @return
	 */
	public synchronized static int differentDays2(Date date1, Date date2) {
		if (date1 == null || date2 == null) {
			return 0;
		}
		LocalDate localDate1 = date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
		LocalDate localDate2 = date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
		Long daysBetween = ChronoUnit.DAYS.between(localDate2, localDate1);
		int days = daysBetween.intValue();
		return days;
	}


    /**
     * 根据当前时间获取本年第一天 格式yyyy-MM-dd
     * @return
     */
    public synchronized static String getYearFirstDay(Date date) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        // 获取前月的第一天
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.YEAR, 0);
        calendar.set(Calendar.DAY_OF_YEAR, 1);
        return format.format(calendar.getTime());
    }

    /**
     * 根据当前时间获取下年第一天 格式yyyy-MM-dd
     * @return
     */
    public synchronized static String getYearNextFirstDay(Date date) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        // 获取前月的第一天
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.YEAR, 1);
        calendar.set(Calendar.DAY_OF_YEAR, 1);
        return format.format(calendar.getTime());
    }

    /**
     * 根据当前时间获取本年第一天 格式yyyy-MM-dd
     * @return
     */
    public synchronized static String getYearFirstDay() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        // 获取前月的第一天
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.YEAR, 0);
        calendar.set(Calendar.DAY_OF_YEAR, 1);
        return format.format(calendar.getTime());
    }

    /**
     * 根据当前时间获取下年第一天 格式yyyy-MM-dd
     * @return
     */
    public synchronized static String getYearNextFirstDay() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        // 获取前月的第一天
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.YEAR, 1);
        calendar.set(Calendar.DAY_OF_YEAR, 1);
        return format.format(calendar.getTime());
    }

    /**
     * 根据当前时间获取本月第一天 格式yyyy-MM-dd
     * @return
     */
    public synchronized static String getMonthFirstDay(Date date) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        // 获取前月的第一天
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return format.format(calendar.getTime());
    }

    /**
     * 根据当前时间获取下月月最后一天 格式yyyy-MM-dd
     * @return
     */
    public synchronized static String getMonthNextFirstDay(Date date) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        // 获取前月的第一天
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return format.format(calendar.getTime());
    }

    /**
     * 根据当前时间获取本月第一天 格式yyyy-MM-dd
     * @return
     */
    public synchronized static String getMonthFirstDay() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        // 获取前月的第一天
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return format.format(calendar.getTime());
    }

    /**
     * 根据当前时间获取下月月最后一天 格式yyyy-MM-dd
     * @return
     */
    public synchronized static String getMonthNextFirstDay() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        // 获取前月的第一天
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return format.format(calendar.getTime());
    }
    /**
     * 根据当前时间获取本月最后一天 格式yyyy-MM-dd
     * @return
     */
    public synchronized static String getMonthLastDay(Date date) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        // 获取前月的第一天
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, 0);
        return format.format(calendar.getTime());
    }

    /**
     * 根据当前时间获取本月最后一天 格式yyyy-MM-dd
     * @return
     */
    public synchronized static String getMonthLastDay() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        // 获取前月的第一天
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, 0);
        return format.format(calendar.getTime());
    }

    /**
     * 根据日期获得星期一
     * @return
     */
    public synchronized static String getWeekBegin(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        // 设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        // 获得当前日期是一个星期的第几天
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
        if(dayWeek==1){
            dayWeek = 8;
        }

        cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - dayWeek);// 根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        Date mondayDate = cal.getTime();
        String weekBegin = sdf.format(mondayDate);
        return weekBegin;
    }

    /**
     * 根据日期获得星期天
     * @return
     */
    public synchronized static String getWeekEnd(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        // 设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        // 获得当前日期是一个星期的第几天
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
        if(dayWeek==1){
            dayWeek = 8;
        }

        cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - dayWeek);// 根据日历的规则，给当前日期减去星期几与一个星期第一天的差值

        cal.add(Calendar.DATE, 4 +cal.getFirstDayOfWeek());
        Date sundayDate = cal.getTime();
        String weekEnd = sdf.format(sundayDate);
        return weekEnd;
    }

    /**
     * 根据日期获得星期
     * @param date
     * @return
     */
    public synchronized static String getWeekOfDate(Date date) {
        String[] weekDaysName = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
        String[] weekDaysCode = { "0", "1", "2", "3", "4", "5", "6" };
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int intWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        return weekDaysName[intWeek];
    }

    /**
     * 根据日期获得星期几，星期天返回0
     * @param date
     * @return
     */
    public synchronized static Integer getWeekOfDateNum(Date date) {
        String[] weekDaysName = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
        String[] weekDaysCode = { "0", "1", "2", "3", "4", "5", "6" };
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int intWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        return intWeek;
    }

    /**
     * 字符串转换成时间
     * @param time
     * @return
     */
    public synchronized static Date convertDate(String time){
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = sdf.parse(time);
            return date;
        } catch (ParseException e) {
            e.printStackTrace();
            return new Date();
        }
    }

    /**
     * 字符串转换成时间
     * @param time
     * @return
     */
    public synchronized static Date convertDate(String time, SimpleDateFormat sdf){
        try {
            Date date = sdf.parse(time);
            return date;
        } catch (ParseException e) {
            e.printStackTrace();
            return new Date();
        }
    }

	public synchronized static Date convertDate(String time, String pattern){
		try {
			SimpleDateFormat sdf = new SimpleDateFormat(pattern);
			Date date = sdf.parse(time);
			return date;
		} catch (ParseException e) {
			e.printStackTrace();
			return new Date();
		}
	}

	public synchronized static Date convertDate2(String time, String... patterns) {
		if (StringUtils.isBlank(time)) {
			return new Date();
		}
		if (patterns == null || patterns.length < 1) {
			patterns = DEFAULT_FORMAT_PATTERS;
		}
		for (String pattern : patterns) {
			try {
				SimpleDateFormat sdf = new SimpleDateFormat(pattern);
				Date date = sdf.parse(time);
				return date;
			} catch (ParseException e) {
				//e.printStackTrace();
				continue;
			}
		}
		return new Date();
	}

    /**
     * 时间转换成字符串
     * @param date
     * @return
     */
    public synchronized static String convertString(Date date){
        try{
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return sdf.format(date);
        } catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 时间转换成字符串
     * @param date
     * @pattern 格式
     * @return
     */
    public synchronized static String convertString(Date date, String pattern){
        try{
            return getDateFormat(pattern).format(date);
        } catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

	public synchronized static String convertString(LocalDateTime date, String pattern){
		String format = date.format(DateTimeFormatter.ofPattern(pattern));
		return format;
	}

    /**
     * 时间字符串转为长整型
     * @param time
     * @return
     */
    public synchronized static Long convertLong(String time){
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = sdf.parse(time);
            return date.getTime();
        } catch (ParseException e) {
            e.printStackTrace();
            return 0L;
        }
    }

    /**
     * 字符串转为整型
     * @param object
     * @return
     */
    public synchronized static Integer convertInteger(Object object){
        if (object == null)
            return 0;
        else
            return Integer.parseInt(object.toString());
    }

    /**
     * 根据传入时间获取几小时以前的时间
     * @param date 时间参数
     * @param hour 小时数
     * @return
     */
    public synchronized static Date convertBeforeHourDate(Date date, Integer hour) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) - hour);
        return calendar.getTime();
    }

    /**
     * 根据传入时间获取几天以前的时间
     * @param date 时间参数
     * @param day 天数
     * @return
     */
    public synchronized static Date convertBeforeDayDate(Date date, Integer day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) - day);
        return calendar.getTime();
    }

    /**
     * 根据传入时间获取几个月以前的时间
     * @param date 时间参数
     * @param month 天数
     * @return
     */
    public synchronized static Date convertBeforeMonthDate(Date date, Integer month) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
		calendar.add(Calendar.MONTH, -month);
		//calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - month);
        return calendar.getTime();
    }

    /**
     * 根据传入时间获取几天以前的时间
     * @param date 时间参数
     * @param min 分钟数
     * @return
     */
    public synchronized static Date convertBeforeMinDate(Date date, Integer min) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) - min);
        return calendar.getTime();
    }

    /**
     * 根据传入时间获取几天以前的时间
     * @param date 时间参数
     * @param year 年
     * @return
     */
    public synchronized static Date convertBeforeYearDate(Date date, Integer year) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) - year);
        return calendar.getTime();
    }

    /**
     * 获取时间转换格式
     * @return
     */
    public synchronized static SimpleDateFormat getDateFormat(String pattern) {
        return new SimpleDateFormat(pattern);
    }

	/**
	 * 判断日期是否在某个区间呢
	 *
	 * @param startTime  区间起始时间
	 * @param endTime    区间截止时间
	 * @param targetTime 目标时间
	 * @return 是否在区间内
	 */
	public static boolean interval(Date startTime, Date endTime, Date targetTime) {
		if (startTime == null || endTime == null || targetTime == null) {
			return false;
		}
		// 定义日期区间
		Calendar startCal = Calendar.getInstance();
		startCal.setTime(startTime);
		Calendar endCal = Calendar.getInstance();
		endCal.setTime(endTime);
		// 将Date转换为Calendar进行比较
		Calendar targetCalendar = Calendar.getInstance();
		targetCalendar.setTime(targetTime);

		// 判断是否在区间内
		if (targetCalendar.after(startCal) && targetCalendar.before(endCal)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 包含等于的情况
	 *
	 * @param startTime
	 * @param endTime
	 * @param targetTime
	 * @return
	 */
	public static boolean intervalE(Date startTime, Date endTime, Date targetTime) {
		if (startTime == null || endTime == null || targetTime == null) {
			return false;
		}
		// 定义日期区间
		Calendar startCal = Calendar.getInstance();
		startCal.setTime(startTime);
		Calendar endCal = Calendar.getInstance();
		endCal.setTime(endTime);
		// 将Date转换为Calendar进行比较
		Calendar targetCalendar = Calendar.getInstance();
		targetCalendar.setTime(targetTime);
		if (targetCalendar.equals(startCal) || targetCalendar.equals(endCal)) {
			return true;
		}
		// 判断是否在区间内
		if (targetCalendar.after(startCal) && targetCalendar.before(endCal)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 转换日期格式
	 *
	 * @param dateValue 日期
	 * @param format1   格式1
	 * @param format2   格式2
	 * @return
	 */
	public static String tranFormat(String dateValue, String format1, String format2) {
		Date date = convertDate(dateValue, format1);
		String s = convertString(date, format2);
		return s;
	}

	/**
	 * 获取两个时间之前的日期数
	 *
	 * @param startDay 开始时间,格式为yyyy-MM-dd
	 * @param endDay   截止时间,格式为yyyy-MM-dd
	 * @return
	 */
	public static List<String> gainDays(String startDay, String endDay) {
		if (StringUtils.isBlank(startDay) || StringUtils.isBlank(endDay)) {
			//	没有参数
			return null;
		}
		//	格式化日期
		Date startDate = DateUtil.convertDate(startDay, DATE_ABBR_FORMATTER);
		Date endDate = DateUtil.convertDate(endDay, DATE_ABBR_FORMATTER);
		List<String> dayList = new ArrayList<>();
		Calendar c = Calendar.getInstance();
		while (startDate.before(endDate) || startDate.equals(endDate)) {
			// 格式化并设到列表
			String s = DateUtil.convertString(startDate, "yyyy-MM-dd");
			dayList.add(s);
			c.setTime(startDate);
			c.set(Calendar.DAY_OF_YEAR, c.get(Calendar.DAY_OF_YEAR) + 1);
			startDate = c.getTime();
		}
		return dayList;
	}
}
